/**
 * @component Models
 * @description 3D模型展示组件，用于展示和交互机械臂模型
 * @features
 * - 支持模型切换（正常/润滑状态）
 * - 支持模型旋转、缩放等交互
 * - 支持润滑动画效果
 * - 支持模型部件提示
 */

<template>
  <!-- 3D模型展示容器 -->
  <div class="models" ref="modelsContainer"></div>
  
  <!-- 提示窗口 -->
  <div 
    v-if="showTooltip" 
    class="tooltip" 
    :style="tooltipStyle"
  >
    {{ tooltipText }}
  </div>

  <!-- 操作菜单 -->
  <div class="menus">
    <div
      class="menu-item"
      :class="{ 'menu-item--active': isLubricationModel }"
      @click="handleModelSwitch"
    >
      切换模型
    </div>
    <div 
      class="menu-item" 
      @click="toggleLubrication"
    >
      {{ isLubricating ? "结束润滑" : "开始润滑" }}
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, reactive, onUnmounted } from "vue";
import * as THREE from "three";
import { MTLLoader } from "three/addons/loaders/MTLLoader.js";
import { OBJLoader } from "three/addons/loaders/OBJLoader.js";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import { FontLoader } from "three/addons/loaders/FontLoader.js";
import { TextGeometry } from "three/addons/geometries/TextGeometry.js";
import { ElMessage } from "element-plus";

// 类型定义
interface TooltipStyle {
  left: string;
  top: string;
}

// 组件状态
const modelsContainer = ref<HTMLElement | null>(null);
const showTooltip = ref(false);
const tooltipText = ref("象鼻梁");
const tooltipStyle = reactive<TooltipStyle>({
  left: "0px",
  top: "0px",
});

// 模型状态
const isLubricationModel = ref(false);
const isLubricating = ref(false);
const modelConfig = reactive({
  mtl: "arm.mtl",
  obj: "arm.obj"
});

// Three.js 相关变量
let camera: THREE.PerspectiveCamera;
let scene: THREE.Scene;
let renderer: THREE.WebGLRenderer;
let controls: OrbitControls;
let animationFrameId: number;
const animationIntervals: number[] = [];

// 模型切换处理
const handleModelSwitch = () => {
  if (isLubricating.value) {
    ElMessage.warning("请先结束润滑！");
    return;
  }
  
  isLubricationModel.value = !isLubricationModel.value;
  modelConfig.mtl = isLubricationModel.value ? "arm_op.mtl" : "arm.mtl";
  modelConfig.obj = isLubricationModel.value ? "arm_op.obj" : "arm.obj";
  
  initScene();
};

// 初始化场景
const initScene = async () => {
  if (!modelsContainer.value) return;
  
  // 清理现有场景
  cleanupScene();
  modelsContainer.value.innerHTML = "";

  // 初始化相机
  initCamera();
  
  // 初始化场景和光照
  initSceneAndLights();
  
  // 加载模型
  await loadModel();
  
  // 初始化渲染器
  initRenderer();
  
  // 初始化控制器
  initControls();
  
  // 添加事件监听
  addEventListeners();
  
  // 开始动画循环
  startAnimationLoop();
};

// 添加线条和提示点相关的变量
let line, tooltipPoint;

// 初始化函数调用 如果在这个地方调用 dom此时没有创建，会出现报错 所以需要将初始化的方法放到 挂载后的生命周期中或者nexttick 这个钩子里面
// init();
onMounted(() => {
  initScene();
  window.addEventListener('resize', handleWindowResize);
});
/**
 * 初始化3D场景
 * 设置相机、场景、光照、加载模型等
 */
async function init() {
  modelsContainer.value.innerHTML = "";
  // 创建透视相机
  // 参数：视场角、宽高比、近平面、远平面
  camera = new THREE.PerspectiveCamera(
    45,
    window.innerWidth / window.innerHeight,
    0.1,
    200
  );
  camera.position.z = 3000; // 设置相机位置
  camera.position.y = -300;
  // 创建场景
  scene = new THREE.Scene();

  // 添加环境光
  const ambientLight = new THREE.AmbientLight("#ff7800", 18);
  scene.add(ambientLight);

  // 添加点光源并跟随相机
  const pointLight = new THREE.PointLight(0xffffff, 15);
  camera.add(pointLight);
  scene.add(camera);

  // 加载模型材质
  const mtlLoader = new MTLLoader().setPath("/tsg_red/");
  const materials = await mtlLoader.loadAsync(modelConfig.mtl);
  materials.preload();

  // 设置所有材质的透明属性
  Object.values(materials.materials).forEach((material) => {
    if (material) {
      material.transparent = true;
      material.opacity = 1; // 可以根据需要调整透明度
    }
  });

  // 加载OBJ模型
  const objLoader = new OBJLoader().setPath("/tsg_red/");
  objLoader.setMaterials(materials); // 设置材质（可选，因为OBJ文件可以不依赖MTL文件）

  // 加载模型并设置位置和缩放
  const object = await objLoader.loadAsync(modelConfig.obj);
  object.position.y = -3.5; // 调整模型位置
  object.position.x = -2;
  object.scale.setScalar(0.0003); // 设置模型缩放
  scene.add(object);
  // 当模型切换后 才显示这个提示线
  if (isLubricationModel.value) {
    // 创建提示点
    // const pointGeometry = new THREE.SphereGeometry(0.1, 32, 32);
    // const pointMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 });
    // tooltipPoint = new THREE.Mesh(pointGeometry, pointMaterial);

    // // 设置提示点位置（这里需要根据实际模型调整坐标）
    // tooltipPoint.position.set(5, 4.25, 0.1);
    // scene.add(tooltipPoint);

    // 创建线条
    const points = [];
    points.push(new THREE.Vector3(5, 4.25, 0.1)); // 起点
    points.push(new THREE.Vector3(2.77, 4.25, 0.1)); // 终点 x y z

    const lineGeometry = new THREE.BufferGeometry().setFromPoints(points);
    const lineMaterial = new THREE.LineBasicMaterial({
      color: 0xff0000,
      linewidth: 2,
    });
    line = new THREE.Line(lineGeometry, lineMaterial);
    scene.add(line);

    // 2. 加载字体
    const fontLoader = new FontLoader();
    fontLoader.load(
      "/myfont1.json",
      (font) => {
        // 3. 创建文字几何体
        const textGeometry = new TextGeometry("象鼻梁", {
          font: font,
          size: 0.3,
          depth:0.05,
          height: 0.1,
          curveSegments: 1,
          bevelEnabled: true,
          bevelThickness: 0.03,
          bevelSize: 0.005,
          bevelOffset: 0,
          bevelSegments: 1,
        });

        // 4. 创建材质
        const textMaterial = new THREE.MeshStandardMaterial({
          color: 0x00ff00,
        });

        // 5. 创建网格并设置位置
        const textMesh = new THREE.Mesh(textGeometry, textMaterial);
        textMesh.position.set(5, 4.25, 0.1); // 设置文字位置 (x, y, z)

        // 6. 添加到场景
        scene.add(textMesh);
      }
    );
  }

  // 创建WebGL渲染器
  renderer = new THREE.WebGLRenderer({
    alpha: true,
    antialias: true,
    preserveDrawingBuffer: true, // 保留绘图缓冲区
  });
  renderer.setClearColor(0x000000, 0); // 设置清除颜色为完全透明
  scene.background = null; // 移除场景背景色
  renderer.setPixelRatio(window.devicePixelRatio); // 设置设备像素比

  //   renderer.setSize(window.innerWidth, window.innerHeight); // 设置渲染尺寸
  renderer.setSize(modelsContainer.value.clientWidth, modelsContainer.value.clientWidth / 2);
  renderer.setAnimationLoop(animate); // 设置动画循环
  //   document.body.appendChild(renderer.domElement);
  modelsContainer.value.appendChild(renderer.domElement); // 将渲染器添加到DOM

  // 创建轨道控制器
  controls = new OrbitControls(camera, renderer.domElement);
  controls.enableDamping = true; // 启用阻尼效果
  controls.minDistance = 2; // 最小缩放距离
  controls.maxDistance = 15; // 最大缩放距离

  // 添加鼠标移动事件监听
  renderer.domElement.addEventListener("mousemove", onMouseMove);
  renderer.domElement.addEventListener("click", onMouseClick);

  // 添加窗口大小变化监听
  window.addEventListener("resize", onWindowResize);
}

/**
 * 处理窗口大小变化
 * 更新相机和渲染器尺寸
 */
function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix(); // 更新相机投影矩阵

  renderer.setSize(window.innerWidth, window.innerHeight); // 更新渲染器尺寸
}

/**
 * 动画循环函数
 * 更新控制器状态并渲染场景
 */
function animate() {
  controls.update(); // 更新控制器
  renderer.render(scene, camera); // 渲染场景
}

// 添加鼠标移动事件处理函数
function onMouseMove(event) {
  const rect = renderer.domElement.getBoundingClientRect();
  const x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
  const y = -((event.clientY - rect.top) / rect.height) * 2 + 1;

  const raycaster = new THREE.Raycaster();
  raycaster.setFromCamera({ x, y }, camera);

  const intersects = raycaster.intersectObject(tooltipPoint);

  if (intersects.length > 0) {

    // showTooltip.value = true;
    showTooltip.value = true;
    tooltipStyle.left = `${event.clientX + 10}px`;
    tooltipStyle.top = `${event.clientY + 10}px`;
  } else {
    showTooltip.value = false;
  }
}

// 添加鼠标点击事件处理函数
function onMouseClick(event) {
  const rect = renderer.domElement.getBoundingClientRect();
  const x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
  const y = -((event.clientY - rect.top) / rect.height) * 2 + 1;

  const raycaster = new THREE.Raycaster();
  raycaster.setFromCamera({ x, y }, camera);

  const intersects = raycaster.intersectObject(tooltipPoint);

  if (intersects.length > 0) {
    // 这里可以添加点击提示点时的交互逻辑
    console.log("点击了提示点");
  }
}

let invArr = [];
// 在组件卸载时移除事件监听
onUnmounted(() => {
  if (renderer && renderer.domElement) {
    renderer.domElement.removeEventListener("mousemove", onMouseMove);
    renderer.domElement.removeEventListener("click", onMouseClick);
  }
  for (let j = 0; j < invArr.length; j++) {
    clearInterval(invArr[j]);
  }
  invArr = [];
});

const rhFlag = ref(false);
function startRunHua() {
  if (!isLubricationModel.value) {
    console.log("请先切换模型！");
    ElMessage({
      message: "请先切换模型！",
      type: "warning",
    });
    return;
  }
  rhFlag.value = !rhFlag.value;

  if (!rhFlag.value) {
    endRunHua();
    return;
  }
  let arr = scene.children[2].children;
  // 定义 3个数组 fpq line dc 分别设置纹理
  const fpqArr = [
    "fpq_bai.jpg",
    "fpq_green.jpg",
    "fpq_red.jpg",
    "fpq_yellow.jpg",
  ];
  const dcArr = ["dc_green.jpg", "dc_red.jpg", "dc_yellow.jpg"];
  const lineArr = ["1.jpg", "2.jpg", "3.jpg", "4.jpg", "5.jpg"];
  for (let i = 0; i < arr.length; i++) {
    if (arr[i].name.indexOf("_fpq") != -1) {
      let index = 0;
      const loader = new THREE.TextureLoader();
      let texture = loader.load("/tsg_red/" + fpqArr[index]);
      arr[i].material.map = texture;
      let tempInv = setInterval(() => {
        index++;
        texture = loader.load("/tsg_red/" + fpqArr[index]);
        arr[i].material.map = texture;
        if (index === fpqArr.length - 1) {
          index = -1;
        }
      }, 1000);
      invArr.push(tempInv);


    } else if (arr[i].name.indexOf("_dc") != -1) {

      let index = 0;
      const loader = new THREE.TextureLoader();
      let texture = loader.load("/tsg_red/" + dcArr[index]);
      arr[i].material.map = texture;
      let tempInv = setInterval(() => {
        index++;
        texture = loader.load("/tsg_red/" + dcArr[index]);
        arr[i].material.map = texture;
        if (index === dcArr.length - 1) {
          index = -1;
        }
      }, 1000);
      invArr.push(tempInv);
    } else if (arr[i].name.indexOf("_line") != -1) {
      let index = 0;
      const loader = new THREE.TextureLoader();
      let texture = loader.load("/tsg_red/" + lineArr[index]);
      texture.wrapS = THREE.RepeatWrapping;
      texture.wrapT = THREE.RepeatWrapping;
      texture.repeat.set(1, 1);
      arr[i].material.map = texture;
      let tempInv = setInterval(() => {
        index++;

        texture = loader.load("/tsg_red/" + lineArr[index]);
        texture.wrapS = THREE.RepeatWrapping;
        texture.wrapT = THREE.RepeatWrapping;
        texture.repeat.set(1, 1);

        arr[i].material.map = texture;
        if (index === lineArr.length - 1) {
          index = -1;
        }
      }, 500);
      invArr.push(tempInv);
    }
  }
}

function endRunHua() {
  if (!isLubricationModel.value) {
    console.log("请先切换模型！");
    return;
  }
  for (let j = 0; j < invArr.length; j++) {
    clearInterval(invArr[j]);
  }
  invArr = [];
  let arr = scene.children[2].children;
  for (let i = 0; i < arr.length; i++) {
    if (arr[i].name.indexOf("_fpq") != -1) {
      const loader = new THREE.TextureLoader();
      let texture = loader.load("/tsg_red/fpq_bai.jpg");
      arr[i].material.map = texture;
    } else if (arr[i].name.indexOf("_dc") != -1) {
      const loader = new THREE.TextureLoader();
      let texture = loader.load("/tsg_red/dc_yellow.jpg");
      arr[i].material.map = texture;
    } else if (arr[i].name.indexOf("_line") != -1) {
      const loader = new THREE.TextureLoader();
      let texture = loader.load("/tsg_red/line_base.jpg");
      texture.wrapS = THREE.RepeatWrapping;
      texture.wrapT = THREE.RepeatWrapping;
      texture.repeat.set(1, 1);
      arr[i].material.map = texture;
    }
  }
}

// 清理场景资源
const cleanupScene = () => {
  if (animationFrameId) {
    cancelAnimationFrame(animationFrameId);
  }
  
  animationIntervals.forEach(clearInterval);
  animationIntervals.length = 0;
  
  if (renderer) {
    renderer.dispose();
  }
  
  if (scene) {
    scene.traverse((object) => {
      if (object instanceof THREE.Mesh) {
        object.geometry.dispose();
        if (Array.isArray(object.material)) {
          object.material.forEach(material => material.dispose());
        } else {
          object.material.dispose();
        }
      }
    });
  }
};

// 组件生命周期钩子
onMounted(() => {
  initScene();
  window.addEventListener('resize', handleWindowResize);
});

onUnmounted(() => {
  cleanupScene();
  window.removeEventListener('resize', handleWindowResize);
  if (renderer?.domElement) {
    renderer.domElement.removeEventListener('mousemove', handleMouseMove);
    renderer.domElement.removeEventListener('click', handleMouseClick);
  }
});
</script>

<style scoped>
.models {
  position: absolute;
  inset: 0;
  width: 100vw;
  height: 100vh;
}

.tooltip {
  position: fixed;
  background-color: rgba(0, 0, 0, 0.8);
  color: white;
  padding: 8px 12px;
  border-radius: 4px;
  font-size: 14px;
  pointer-events: none;
  z-index: 1100;
  max-width: 200px;
  word-wrap: break-word;
}

.menus {
  position: absolute;
  z-index: 1000;
  left: 50%;
  bottom: 20px;
  transform: translateX(-50%);
  display: flex;
  gap: 10px;
  justify-content: center;
  width: 40%;
  height: 50px;
}

.menu-item {
  width: 80px;
  height: 40px;
  background-image: url("/layout/wei.png");
  background-position: center;
  background-size: 100% 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  color: #fff;
  font-size: 16px;
  cursor: pointer;
  transition: background-image 0.3s ease;
}

.menu-item:hover,
.menu-item--active {
  background-image: url("/layout/zhong.png");
}
</style>
